

package com.maoshi.shop.security.api.filter;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.core.util.StrUtil;
import com.maoshi.shop.bean.enums.SmsType;
import com.maoshi.shop.common.exception.MaoshiShopBindException;
import com.maoshi.shop.security.api.model.MaoshiUser;
import com.maoshi.shop.security.api.service.AppLoginService;
import com.maoshi.shop.security.api.service.MaoshiUserDetailsService;
import com.maoshi.shop.security.api.util.SecurityUtils;
import com.maoshi.shop.security.comment.enums.App;
import com.maoshi.shop.security.comment.exception.BadCredentialsException;
import com.maoshi.shop.security.comment.exception.UsernameNotFoundException;
import com.maoshi.shop.security.comment.filter.MaoshiAuthenticationProcessingFilter;
import com.maoshi.shop.security.comment.token.AuthenticationToken;
import com.maoshi.shop.service.SmsLogService;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * 这里的登录，会有两种情况
 * 1. 账号密码 + 验证码登录
 * 2. 短信登陆
 *
 * 也就是说，只要是正常的登陆，一般都写在这里，
 * 而像微信小程序登陆，微信公众号登陆，qq登陆，新浪微博登陆，google账号登陆，facebook登陆，都在
 * com.maoshi.shop.security.api.filter.AppLoginAuthenticationFilter
 *
 * @author LGH
 */
@Component
public class LoginAuthenticationFilter extends MaoshiAuthenticationProcessingFilter {

    private final MaoshiUserDetailsService maoshiUserDetailsService;

    private final PasswordEncoder passwordEncoder;

    private final SmsLogService smsLogService;

    private final WxMaService wxMaService;

    private final WxMpService wxMpService;

    @Autowired
    public LoginAuthenticationFilter(MaoshiUserDetailsService maoshiUserDetailsService, PasswordEncoder passwordEncoder, SmsLogService smsLogService, WxMaService wxMaService, WxMpService wxMpService) {
        super("/login");
        this.maoshiUserDetailsService = maoshiUserDetailsService;
        this.passwordEncoder = passwordEncoder;
        this.smsLogService = smsLogService;
        this.wxMaService = wxMaService;
        this.wxMpService = wxMpService;
    }

    @Override
    protected UserDetails getUserDetails(AuthenticationToken authentication) {
        // 验证码登录
        if (Objects.equals(authentication.getLoginType(), 1)) {
            if (!smsLogService.checkValidCode(authentication.getPrincipal(), String.valueOf(authentication.getCredentials()), SmsType.LOGIN)){
                throw new MaoshiShopBindException("验证码有误或已过期");
            }
        }
        // 用户名或手机号，一般的登陆都是通过Principal传过来的
        // 但是微信公众号支付，小程序支付都需要openid，如果单纯的使用账号密码登陆，会导致无法进行支付，所以要通过微信的code获取openId放到当前登录的用户上
        String userNameOrMobile = authentication.getPrincipal();
        String code = null;

        // 在
        if (Objects.equals(authentication.getAppType(), App.MINI.value())
         || Objects.equals(authentication.getAppType(), App.MP.value())) {

            if (!authentication.getPrincipal().contains(StrUtil.COLON)) {
                throw new MaoshiShopBindException("登陆信息异常");
            }
            String[] principalInfo = authentication.getPrincipal().split(StrUtil.COLON);

            userNameOrMobile = principalInfo[0];
            code = principalInfo[1];
        }

        MaoshiUser user;
        try {
            user = maoshiUserDetailsService.loadUserByMobileOrUserName(userNameOrMobile, authentication.getAppType(),authentication.getLoginType());
        } catch (UsernameNotFoundException var6) {
            throw new UsernameNotFoundException("账号或密码不正确");
        }
        if (!user.isEnabled()) {
            throw new UsernameNotFoundException("账号已被锁定,请联系管理员");
        }

        // 非验证码登录 也就是账号密码登录
        if (!Objects.equals(authentication.getLoginType(), 1)) {
            String encodedPassword = user.getPassword();
            String rawPassword = authentication.getCredentials().toString();
            // 密码不正确
            if (StrUtil.isBlank(encodedPassword) || !passwordEncoder.matches(rawPassword,encodedPassword)){
                throw new BadCredentialsException("账号或密码不正确");
            }
        }


        if (StrUtil.isNotBlank(code)) {
            try {
                // 小程序携带code登录
                if (Objects.equals(authentication.getAppType(), App.MINI.value())) {
                    WxMaJscode2SessionResult session = wxMaService.getUserService().getSessionInfo(code);
                    user.setSessionKey(session.getSessionKey());
                    user.setBizUserId(session.getOpenid());
                }
                // 公众号携带code登录
                if (Objects.equals(authentication.getAppType(), App.MP.value())) {
                    WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code);
                    user.setBizUserId(wxMpOAuth2AccessToken.getOpenId());
                }
            } catch (me.chanjar.weixin.common.error.WxErrorException e) {
                throw new MaoshiShopBindException(e.getMessage());
            }
        }


        return user;
    }


}
